home *** CD-ROM | disk | FTP | other *** search
/ AMIGA-CD 2 / Amiga-CD - Volume 2.iso / gepackte_disketten / 1994 / 08_94_5.dms / 08_94_5.adf / term-4.0-Source.lha / termTextBuffer.c < prev    next >
C/C++ Source or Header  |  1994-06-27  |  42KB  |  1,903 lines

  1. /*
  2. **    termTextBuffer.c
  3. **
  4. **    Support routines for the text buffer.
  5. **
  6. **    Copyright © 1990-1994 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Gadget ID codes. */
  13.  
  14. enum    {    GAD_SCROLLER,GAD_UP,GAD_DOWN };
  15.  
  16.     /* Menu ID codes. */
  17.  
  18. enum    {    MEN_SEARCH,MEN_REPEAT,MEN_GOTO,MEN_CLEARBUF_CONTENTS,MEN_QUITBUF };
  19.  
  20.     /* Gadget ID codes. */
  21.  
  22. enum    {    GAD_STRING,GAD_LOAD,GAD_OK,GAD_CANCEL };
  23.  
  24.     /* A handy macro to determine the length of a string. */
  25.  
  26. #define LINE_WIDTH(s)    (s)[-1]
  27.  
  28.     /* The dimensions of the scroller images. */
  29.  
  30. #define ARROW_WIDTH    18
  31. #define ARROW_HEIGHT    11
  32.  
  33. STATIC struct NewMenu BufferMenu[] =
  34. {
  35.     { NM_TITLE, NULL,         0 , 0, 0, (APTR)0},
  36.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_SEARCH},
  37.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_REPEAT},
  38.     {  NM_ITEM, NM_BARLABEL,     0 , 0, 0, (APTR)0},
  39.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_GOTO},
  40.     {  NM_ITEM, NM_BARLABEL,     0 , 0, 0, (APTR)0},
  41.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_CLEARBUF_CONTENTS},
  42.     {  NM_ITEM, NM_BARLABEL,     0 , 0, 0, (APTR)0},
  43.     {  NM_ITEM, NULL,         0 , 0, 0, (APTR)MEN_QUITBUF},
  44.  
  45.     { NM_END, 0,             0 , 0, 0, (APTR)0}
  46. };
  47.  
  48.     /* Some private data (render info & window). */
  49.  
  50. STATIC struct Window        *BufferWindow;
  51. STATIC struct Screen        *BufferScreen;
  52. STATIC struct Menu        *BufferMenuStrip;
  53.  
  54. STATIC struct RastPort        *BPort;
  55. STATIC APTR             BufferVisualInfo;
  56.  
  57. STATIC LONG             NumBufferLines,
  58.                  NumBufferColumns,
  59.                  LastTopLine;
  60.  
  61. STATIC struct DrawInfo        *BufferDrawInfo;
  62. STATIC struct Image        *BufferAmigaGlyph,
  63.                 *BufferCheckGlyph;
  64.  
  65. STATIC BYTE             BufferTerminated;
  66.  
  67. STATIC WORD             LocalTextFontWidth,
  68.                  LocalTextFontHeight,
  69.                  LocalTextFontBase;
  70.  
  71. STATIC struct TTextAttr         LocalTextFont;
  72. STATIC UBYTE __far         LocalTextFontName[MAX_FILENAME_LENGTH];
  73.  
  74. STATIC struct TTextAttr         LocalUserFont;
  75. STATIC UBYTE __far         LocalUserFontName[MAX_FILENAME_LENGTH];
  76.  
  77. STATIC LONG             TopLine = -1,
  78.                  DisplayedLines;
  79.  
  80. STATIC struct SearchInfo    *BufferSearchInfo;
  81. STATIC BYTE             SearchForward    = TRUE,
  82.                  IgnoreCase    = TRUE;
  83.  
  84. STATIC struct Gadget        *Scroller,
  85.                 *UpArrow,
  86.                 *DownArrow;
  87.  
  88. STATIC struct Image        *UpImage,
  89.                 *DownImage;
  90.  
  91. STATIC UWORD            *BufferLineWidths,
  92.                 *BufferLineOffsets,
  93.                 *BufferColumnOffsets;
  94.  
  95.     /* DeleteScroller(VOID):
  96.      *
  97.      *    Delete scroller and arrow objects.
  98.      */
  99.  
  100. STATIC VOID
  101. DeleteScroller(VOID)
  102. {
  103.     if(Scroller)
  104.     {
  105.         DisposeObject(Scroller);
  106.  
  107.         Scroller = NULL;
  108.     }
  109.  
  110.     if(UpArrow)
  111.     {
  112.         DisposeObject(UpArrow);
  113.  
  114.         UpArrow = NULL;
  115.     }
  116.  
  117.     if(DownArrow)
  118.     {
  119.         DisposeObject(DownArrow);
  120.  
  121.         DownArrow = NULL;
  122.     }
  123.  
  124.     if(UpImage)
  125.     {
  126.         DisposeObject(UpImage);
  127.  
  128.         UpImage = NULL;
  129.     }
  130.  
  131.     if(DownImage)
  132.     {
  133.         DisposeObject(DownImage);
  134.  
  135.         DownImage = NULL;
  136.     }
  137. }
  138.  
  139.     /* CreateScroller(LONG Height):
  140.      *
  141.      *    Create scroller and arrow objects.
  142.      */
  143.  
  144. STATIC BYTE __regargs
  145. CreateScroller(LONG Height)
  146. {
  147.     struct DrawInfo    *DrawInfo;
  148.     BYTE         Result = FALSE;
  149.  
  150.     if(DrawInfo = GetScreenDrawInfo(BufferScreen))
  151.     {
  152.         if(UpImage = (struct Image *)NewObject(NULL,"sysiclass",
  153.             SYSIA_Size,    SYSISIZE_MEDRES,
  154.             SYSIA_Which,    UPIMAGE,
  155.             SYSIA_DrawInfo,    DrawInfo,
  156.         TAG_DONE))
  157.         {
  158.             if(DownImage = (struct Image *)NewObject(NULL,"sysiclass",
  159.                 SYSIA_Size,    SYSISIZE_MEDRES,
  160.                 SYSIA_Which,    DOWNIMAGE,
  161.                 SYSIA_DrawInfo,    DrawInfo,
  162.             TAG_DONE))
  163.             {
  164.                 LONG ScrollerHeight,LeftEdge;
  165.  
  166.                 ScrollerHeight = Height - 2 * ARROW_HEIGHT;
  167.  
  168.                 LeftEdge = BufferScreen -> Width - ARROW_WIDTH;
  169.  
  170.                 if(Scroller = NewObject(NULL,"propgclass",
  171.                     GA_ID,        GAD_SCROLLER,
  172.  
  173.                     GA_Top,        0,
  174.                     GA_Left,    LeftEdge,
  175.                     GA_Width,    ARROW_WIDTH,
  176.                     GA_Height,    ScrollerHeight,
  177.                     GA_Immediate,    TRUE,
  178.                     GA_FollowMouse,    TRUE,
  179.                     GA_RelVerify,    TRUE,
  180.  
  181.                     PGA_Freedom,    FREEVERT,
  182.                     PGA_NewLook,    TRUE,
  183.  
  184.                     PGA_Visible,    1,
  185.                     PGA_Total,    1,
  186.                 TAG_DONE))
  187.                 {
  188.                     STATIC struct TagItem ArrowMappings[] = { GA_ID,GA_ID,TAG_END };
  189.  
  190.                     if(UpArrow = NewObject(NULL,"buttongclass",
  191.                         GA_ID,        GAD_UP,
  192.                         GA_Image,    UpImage,
  193.                         GA_Left,    LeftEdge,
  194.                         GA_Top,        ScrollerHeight,
  195.                         GA_Height,    ARROW_HEIGHT,
  196.                         GA_Width,    ARROW_WIDTH,
  197.                         GA_Immediate,    TRUE,
  198.                         GA_RelVerify,    TRUE,
  199.                         GA_Previous,    Scroller,
  200.  
  201.                         ICA_TARGET,    ICTARGET_IDCMP,
  202.                         ICA_MAP,    ArrowMappings,
  203.                     TAG_DONE))
  204.                     {
  205.                         if(DownArrow = NewObject(NULL,"buttongclass",
  206.                             GA_ID,        GAD_DOWN,
  207.                             GA_Image,    DownImage,
  208.                             GA_Left,    LeftEdge,
  209.                             GA_Top,        ScrollerHeight + ARROW_HEIGHT,
  210.                             GA_Height,    ARROW_HEIGHT,
  211.                             GA_Width,    ARROW_WIDTH,
  212.                             GA_Immediate,    TRUE,
  213.                             GA_RelVerify,    TRUE,
  214.                             GA_Previous,    UpArrow,
  215.  
  216.                             ICA_TARGET,    ICTARGET_IDCMP,
  217.                             ICA_MAP,    ArrowMappings,
  218.                         TAG_DONE))
  219.                             Result = TRUE;
  220.                     }
  221.                 }
  222.             }
  223.         }
  224.  
  225.         FreeScreenDrawInfo(BufferScreen,DrawInfo);
  226.     }
  227.  
  228.     if(!Result)
  229.         DeleteScroller();
  230.  
  231.     return(Result);
  232. }
  233.  
  234.     /* PrintLine(STRPTR Buffer,LONG LineNumber):
  235.      *
  236.      *    Print a line at a given line number in the displayed area.
  237.      */
  238.  
  239. STATIC VOID __regargs
  240. PrintLine(STRPTR Buffer,LONG LineNumber)
  241. {
  242.     WORD Length = Buffer[-1];
  243.  
  244.         /* Print the text. */
  245.  
  246.     if(Length)
  247.     {
  248.         Move(BPort,0,BufferLineOffsets[LineNumber] + LocalTextFontBase);
  249.  
  250.         if(Length > NumBufferColumns)
  251.             Length = NumBufferColumns;
  252.  
  253.         Text(BPort,Buffer,Length);
  254.     }
  255.  
  256.         /* The line doesn't exactly fill the displayed line,
  257.          * so erase the remaining columns.
  258.          */
  259.  
  260.     if(Length < BufferLineWidths[LineNumber])
  261.     {
  262.         SetAPen(BPort,0);
  263.         RectFill(BPort,BufferColumnOffsets[Length],BufferLineOffsets[LineNumber],BufferColumnOffsets[BufferLineWidths[LineNumber]] - 1,BufferLineOffsets[LineNumber + 1] - 1);
  264.         SetAPen(BPort,1);
  265.     }
  266.  
  267.     BufferLineWidths[LineNumber] = Length;
  268. }
  269.  
  270.     /* RedrawScreen(LONG FirstLine):
  271.      *
  272.      *    Redraw the contents of the entire screen and return the
  273.      *    number of lines actually drawn.
  274.      */
  275.  
  276. STATIC LONG __regargs
  277. RedrawScreen(LONG FirstLine)
  278. {
  279.     LONG i,Last,Line = 0,Result;
  280.  
  281.     ObtainSemaphore(BufferSemaphore);
  282.  
  283.         /* Determine last line to display. */
  284.  
  285.     if((Last = FirstLine + NumBufferLines) >= Lines)
  286.         Last = Lines;
  287.  
  288.     Result = Last - FirstLine;
  289.  
  290.     if(Lines)
  291.     {
  292.         if(LastTopLine != -1)
  293.         {
  294.             LONG Delta = FirstLine - LastTopLine;
  295.  
  296.             if(ABS(Delta) < NumBufferLines)
  297.             {
  298.                     /* No change? */
  299.  
  300.                 if(!Delta)
  301.                 {
  302.                     ReleaseSemaphore(BufferSemaphore);
  303.  
  304.                     return(Result);
  305.                 }
  306.                 else
  307.                 {
  308.                     LastTopLine = FirstLine;
  309.  
  310.                         /* Scrolled up? */
  311.  
  312.                     if(Delta < 0)
  313.                     {
  314.                         for(i = NumBufferLines - 1 ; i >= -Delta ; i--)
  315.                             BufferLineWidths[i] = BufferLineWidths[i + Delta];
  316.  
  317.                         ClipBlit(BPort,0,0,BPort,0,BufferLineOffsets[-Delta],BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines + Delta],MINTERM_COPY);
  318.  
  319.                         Last = FirstLine - Delta;
  320.                     }
  321.                     else
  322.                     {
  323.                         for(i = Delta ; i < NumBufferLines ; i++)
  324.                             BufferLineWidths[i - Delta] = BufferLineWidths[i];
  325.  
  326.                             /* Scrolled down. */
  327.  
  328.                         ClipBlit(BPort,0,BufferLineOffsets[Delta],BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - Delta],MINTERM_COPY);
  329.  
  330.                         FirstLine += NumBufferLines - Delta;
  331.  
  332.                         Line = NumBufferLines - Delta;
  333.                     }
  334.                 }
  335.             }
  336.             else
  337.                 LastTopLine = FirstLine;
  338.         }
  339.         else
  340.             LastTopLine = FirstLine;
  341.  
  342.         if(BufferLines)
  343.         {
  344.             for(i = FirstLine ; i < Last ; i++)
  345.                 PrintLine(BufferLines[i],Line++);
  346.         }
  347.     }
  348.  
  349.     ReleaseSemaphore(BufferSemaphore);
  350.  
  351.         /* We didn't fill the whole screen, so clear the rest. */
  352.  
  353.     if(Result < NumBufferLines)
  354.     {
  355.         WORD i;
  356.  
  357.         for(i = Result ; i < NumBufferLines ; i++)
  358.             BufferLineWidths[i] = 0;
  359.  
  360.         SetAPen(BPort,0);
  361.         RectFill(BPort,0,BufferLineOffsets[Result],BufferColumnOffsets[NumBufferColumns] - 1,BufferLineOffsets[NumBufferLines] - 1);
  362.         SetAPen(BPort,1);
  363.     }
  364.  
  365.     return(Result);
  366. }
  367.  
  368.     /* MarkArea(LONG Column,LONG Line,LONG Length):
  369.      *
  370.      *    Mark an area in the term Buffer window.
  371.      */
  372.  
  373. STATIC VOID __regargs
  374. MarkArea(LONG Column,LONG Line,LONG Length)
  375. {
  376.     STATIC LONG OldColumn = -1,OldLine = -1,OldLength = -1;
  377.  
  378.     if(OldColumn != -1)
  379.         ClipBlit(BPort,0,0,BPort,BufferColumnOffsets[OldColumn],BufferLineOffsets[OldLine],BufferColumnOffsets[OldLength],LocalTextFontHeight,MINTERM_NOT_C);
  380.  
  381.     if(Column != -1)
  382.     {
  383.         if(OldColumn != Column || OldLine != Line || OldLength != Length)
  384.             ClipBlit(BPort,0,0,BPort,BufferColumnOffsets[Column],BufferLineOffsets[Line],BufferColumnOffsets[Length],LocalTextFontHeight,MINTERM_NOT_C);
  385.     }
  386.  
  387.     OldColumn    = Column;
  388.     OldLine        = Line;
  389.     OldLength    = Length;
  390. }
  391.  
  392.     /* BufferClipPage(struct BlockMarker *Marker):
  393.      *
  394.      *    Send the marked area to the clipboard.
  395.      */
  396.  
  397. STATIC VOID __inline
  398. BufferClipPage(struct BlockMarker *Marker)
  399. {
  400.     if(BufferLines)
  401.     {
  402.         struct IFFHandle *Handle;
  403.  
  404.         if(Handle = AllocIFF())
  405.         {
  406.             if(Handle -> iff_Stream = (ULONG)OpenClipboard(Config -> ClipConfig -> ClipboardUnit))
  407.             {
  408.                 InitIFFasClip(Handle);
  409.  
  410.                 if(!OpenIFF(Handle,IFFF_WRITE))
  411.                 {
  412.                     if(!PushChunk(Handle,ID_FTXT,ID_FORM,IFFSIZE_UNKNOWN))
  413.                     {
  414.                         if(!PushChunk(Handle,0,ID_CHRS,IFFSIZE_UNKNOWN))
  415.                         {
  416.                             LONG    Lines = Marker -> LastLine - Marker -> FirstLine - 1,
  417.                                 i;
  418.  
  419.                             if(LINE_WIDTH(BufferLines[Marker -> FirstLine]) > Marker -> FirstColumn)
  420.                                 WriteTrimmedString(Handle,&BufferLines[Marker -> FirstLine][Marker -> FirstColumn],LINE_WIDTH(BufferLines[Marker -> FirstLine]) - Marker -> FirstColumn);
  421.  
  422.                             WriteChunkBytes(Handle,"\n",1);
  423.  
  424.                             if(Lines > 0)
  425.                             {
  426.                                 for(i = 0 ; i < Lines ; i++)
  427.                                 {
  428.                                     if(LINE_WIDTH(BufferLines[Marker -> FirstLine + 1 + i]))
  429.                                         WriteTrimmedString(Handle,BufferLines[Marker -> FirstLine + 1 + i],LINE_WIDTH(BufferLines[Marker -> FirstLine + 1 + i]));
  430.  
  431.                                     WriteChunkBytes(Handle,"\n",1);
  432.                                 }
  433.                             }
  434.  
  435.                             if(Marker -> LastColumn > LINE_WIDTH(BufferLines[Marker -> LastLine]))
  436.                                 WriteTrimmedString(Handle,BufferLines[Marker -> LastLine],LINE_WIDTH(BufferLines[Marker -> LastLine]));
  437.                             else
  438.                                 WriteTrimmedString(Handle,BufferLines[Marker -> LastLine],Marker -> LastColumn);
  439.  
  440.                             WriteChunkBytes(Handle,"\n",1);
  441.  
  442.                             PopChunk(Handle);
  443.                         }
  444.  
  445.                         PopChunk(Handle);
  446.                     }
  447.  
  448.                     CloseIFF(Handle);
  449.                 }
  450.  
  451.                 CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream);
  452.             }
  453.  
  454.             FreeIFF(Handle);
  455.         }
  456.     }
  457. }
  458.  
  459.     /* BufferClip(VOID):
  460.      *
  461.      *    Start buffer marking process.
  462.      */
  463.  
  464. STATIC VOID
  465. BufferClip(VOID)
  466. {
  467.     struct BlockMarker    *Marker;
  468.     LONG             FirstX = BufferWindow -> MouseX / LocalTextFontWidth,
  469.                  FirstY = BufferWindow -> MouseY / LocalTextFontHeight;
  470.  
  471.     if(Marker = BM_SetMark(BufferWindow -> RPort,ToggleSelect,ToggleSelect,NumBufferColumns,NumBufferLines,0,0,TopLine,Lines,BufferWindow -> MouseX / LocalTextFontWidth,BufferWindow -> MouseY / LocalTextFontHeight,LocalTextFontWidth,LocalTextFontHeight))
  472.     {
  473.         struct IntuiMessage    *Massage;
  474.         ULONG             Code,IClass;
  475.         BYTE             Done = FALSE,Aborted = FALSE;
  476.         LONG             PlusX = LocalTextFontWidth - 1,
  477.                      MouseX,MouseY,
  478.                      Delta = 0;
  479.  
  480.         ReportMouse(TRUE,BufferWindow);
  481.  
  482.         while(!Done)
  483.         {
  484.             WaitPort(BufferWindow -> UserPort);
  485.  
  486.             while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
  487.             {
  488.                 IClass    = Massage -> Class;
  489.                 Code    = Massage -> Code;
  490.                 MouseX    = Massage -> MouseX;
  491.                 MouseY    = Massage -> MouseY;
  492.  
  493.                 ReplyMsg(Massage);
  494.  
  495.                 if(IClass == IDCMP_INACTIVEWINDOW)
  496.                 {
  497.                     Done = Aborted = TRUE;
  498.  
  499.                     break;
  500.                 }
  501.  
  502.                 if(IClass == IDCMP_INTUITICKS && Delta != 0)
  503.                 {
  504.                     if(BufferLines)
  505.                     {
  506.                         if((Delta > 0 && TopLine + NumBufferLines < Lines) || (Delta < 0 && TopLine > 0))
  507.                         {
  508.                             if(Delta < 0)
  509.                             {
  510.                                 WORD i;
  511.  
  512.                                 for(i = NumBufferLines - 1 ; i > -Delta ; i--)
  513.                                     BufferLineWidths[i] = BufferLineWidths[i + Delta];
  514.  
  515.                                 if(DisplayedLines)
  516.                                     ClipBlit(BPort,0,0,BPort,0,LocalTextFontHeight,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  517.  
  518.                                 BufferLineWidths[0] = NumBufferColumns;
  519.  
  520.                                 PrintLine(BufferLines[--TopLine],0);
  521.                             }
  522.                             else
  523.                             {
  524.                                 WORD i;
  525.  
  526.                                 for(i = Delta ; i < NumBufferLines ; i++)
  527.                                     BufferLineWidths[i - Delta] = BufferLineWidths[i];
  528.  
  529.                                 if(DisplayedLines)
  530.                                     ClipBlit(BPort,0,LocalTextFontHeight,BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  531.  
  532.                                 BufferLineWidths[NumBufferLines - 1] = NumBufferColumns;
  533.  
  534.                                 PrintLine(BufferLines[TopLine + NumBufferLines],NumBufferLines - 1);
  535.  
  536.                                 TopLine++;
  537.                             }
  538.  
  539.                             Marker -> Top += Delta;
  540.                             Marker -> LastY -= Delta;
  541.  
  542.                             BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,Delta);
  543.                         }
  544.                         else
  545.                             Delta = 0;
  546.                     }
  547.                 }
  548.  
  549.                 if(IClass == IDCMP_MOUSEBUTTONS && (Code & IECODE_UP_PREFIX))
  550.                 {
  551.                     BM_Draw(Marker,Marker -> Unselect);
  552.  
  553.                     Done = TRUE;
  554.  
  555.                     break;
  556.                 }
  557.  
  558.                 if(IClass == IDCMP_MOUSEMOVE)
  559.                 {
  560.                     BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,0);
  561.  
  562.                     if(MouseY < 1)
  563.                     {
  564.                         if(TopLine > 0)
  565.                             Delta = -1;
  566.                     }
  567.                     else
  568.                     {
  569.                         if(MouseY >= BufferWindow -> Height - 1 && TopLine + NumBufferLines < Lines)
  570.                             Delta = 1;
  571.                     }
  572.  
  573.                     while(Delta)
  574.                     {
  575.                         MouseX    = Window -> MouseX;
  576.                         MouseY    = Window -> MouseY;
  577.  
  578.                         if((Delta < 0 && MouseY > 0) || (Delta > 0 && MouseY < BufferWindow -> Height - 1))
  579.                             break;
  580.                         else
  581.                         {
  582.                             if(BufferLines)
  583.                             {
  584.                                 if((Delta > 0 && TopLine + NumBufferLines < Lines) || (Delta < 0 && TopLine > 0))
  585.                                 {
  586.                                     if(Delta < 0)
  587.                                     {
  588.                                         WORD i;
  589.  
  590.                                         for(i = NumBufferLines - 1 ; i > -Delta ; i--)
  591.                                             BufferLineWidths[i] = BufferLineWidths[i + Delta];
  592.  
  593.                                         if(DisplayedLines)
  594.                                             ClipBlit(BPort,0,0,BPort,0,LocalTextFontHeight,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  595.  
  596.                                         BufferLineWidths[0] = NumBufferColumns;
  597.  
  598.                                         PrintLine(BufferLines[--TopLine],0);
  599.                                     }
  600.                                     else
  601.                                     {
  602.                                         WORD i;
  603.  
  604.                                         for(i = Delta ; i < NumBufferLines ; i++)
  605.                                             BufferLineWidths[i - Delta] = BufferLineWidths[i];
  606.  
  607.                                         if(DisplayedLines)
  608.                                             ClipBlit(BPort,0,LocalTextFontHeight,BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  609.  
  610.                                         BufferLineWidths[NumBufferLines - 1] = NumBufferColumns;
  611.  
  612.                                         PrintLine(BufferLines[TopLine + NumBufferLines],NumBufferLines - 1);
  613.  
  614.                                         TopLine++;
  615.                                     }
  616.  
  617.                                     Marker -> Top    += Delta;
  618.                                     Marker -> LastY    -= Delta;
  619.  
  620.                                     BM_ExtendMark(Marker,(MouseX + PlusX) / LocalTextFontWidth,MouseY / LocalTextFontHeight,Delta);
  621.  
  622.                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  623.                                         PGA_Top,TopLine,
  624.                                     TAG_DONE);
  625.                                 }
  626.                                 else
  627.                                     break;
  628.                             }
  629.                             else
  630.                                 break;
  631.                         }
  632.                     }
  633.  
  634.                     Delta = 0;
  635.                 }
  636.             }
  637.         }
  638.  
  639.         ReportMouse(FALSE,BufferWindow);
  640.  
  641.         while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
  642.             ReplyMsg(Massage);
  643.  
  644.         if(!Aborted)
  645.         {
  646.             if(FirstX != BufferWindow -> MouseX / LocalTextFontWidth || FirstY != BufferWindow -> MouseY / LocalTextFontHeight)
  647.             {
  648.                 SetWait(BufferWindow);
  649.  
  650.                 if(Marker -> FirstColumn == Marker -> Width)
  651.                 {
  652.                     Marker -> FirstLine++;
  653.  
  654.                     Marker -> FirstColumn = 0;
  655.                 }
  656.  
  657.                 if(Marker -> LastColumn == 0)
  658.                 {
  659.                     Marker -> LastLine--;
  660.  
  661.                     Marker -> LastColumn = Marker -> Width;
  662.                 }
  663.  
  664.                 if(Marker -> FirstLine <= Marker -> LastLine)
  665.                 {
  666.                     if(Marker -> FirstLine != Marker -> LastLine || Marker -> FirstColumn != Marker -> LastColumn)
  667.                     {
  668.                         if(BufferLines)
  669.                         {
  670.                             if(Marker -> FirstLine == Marker -> LastLine)
  671.                                 SaveClip(&BufferLines[Marker -> FirstLine][Marker -> FirstColumn],Marker -> LastColumn - Marker -> FirstColumn);
  672.                             else
  673.                                 BufferClipPage(Marker);
  674.                         }
  675.                     }
  676.                 }
  677.  
  678.                 ClrWait(BufferWindow);
  679.             }
  680.         }
  681.  
  682.         FreeVecPooled(Marker);
  683.     }
  684. }
  685.  
  686.     /* StartBufferSearch(BYTE NewSearchString):
  687.      *
  688.      *    Search the buffer for a string.
  689.      */
  690.  
  691. STATIC VOID __regargs
  692. StartBufferSearch(BYTE NewSearchString)
  693. {
  694.     LT_LockWindow(BufferWindow);
  695.  
  696.     if(Lines)
  697.     {
  698.         STATIC UBYTE __far SearchBuffer[256];
  699.  
  700.         BYTE StartSearch = TRUE;
  701.  
  702.         if(NewSearchString || !SearchBuffer[0])
  703.         {
  704.             struct Hook HistoryHook;
  705.  
  706.             HistoryHook . h_Data = &TextBufferHistory;
  707.  
  708.             if(GetSearchString(BufferWindow,&BufferTerminated,SearchBuffer,&HistoryHook,&SearchForward,&IgnoreCase))
  709.             {
  710.                 if(SearchBuffer[0])
  711.                 {
  712.                     if(BufferSearchInfo)
  713.                         DeleteSearchInfo(BufferSearchInfo);
  714.  
  715.                     BufferSearchInfo = CreateSearchInfo(SearchBuffer,SearchForward,IgnoreCase);
  716.                 }
  717.                 else
  718.                     StartSearch = FALSE;
  719.             }
  720.             else
  721.                 StartSearch = FALSE;
  722.         }
  723.         else
  724.         {
  725.             if(!BufferSearchInfo)
  726.                 BufferSearchInfo = CreateSearchInfo(SearchBuffer,TRUE,TRUE);
  727.         }
  728.  
  729.         if(StartSearch && BufferSearchInfo)
  730.         {
  731.             LONG LineNumber;
  732.  
  733.             ObtainSemaphore(BufferSemaphore);
  734.  
  735.             LineNumber = SearchTextBuffer(BufferSearchInfo);
  736.  
  737.             ReleaseSemaphore(BufferSemaphore);
  738.  
  739.             if(LineNumber == -1)
  740.             {
  741.                 BlockWindows();
  742.  
  743.                 MyEasyRequest(BufferWindow,LocaleString(MSG_TERMBUFFER_DID_NOT_FIND_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),SearchBuffer);
  744.  
  745.                 ReleaseWindows();
  746.  
  747.                 FlushMsg(BufferWindow);
  748.  
  749.                 BufferSearchInfo -> FoundY = -1;
  750.  
  751.                 MarkArea(-1,-1,-1);
  752.             }
  753.             else
  754.             {
  755.                 if(LineNumber < TopLine)
  756.                 {
  757.                     MarkArea(-1,-1,-1);
  758.  
  759.                     DisplayedLines = RedrawScreen(TopLine = LineNumber);
  760.  
  761.                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  762.                         PGA_Top,TopLine,
  763.                     TAG_DONE);
  764.                 }
  765.                 else
  766.                 {
  767.                     if(LineNumber > TopLine + DisplayedLines - 1)
  768.                     {
  769.                         MarkArea(-1,-1,-1);
  770.  
  771.                         if(LineNumber >= Lines - NumBufferLines)
  772.                         {
  773.                             LONG NewCurrentLine;
  774.  
  775.                             if((NewCurrentLine = Lines - NumBufferLines) < 0)
  776.                                 NewCurrentLine = 0;
  777.  
  778.                             if(TopLine != NewCurrentLine)
  779.                                 DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
  780.                         }
  781.                         else
  782.                             DisplayedLines = RedrawScreen(TopLine = LineNumber);
  783.  
  784.                         SetGadgetAttrs(Scroller,BufferWindow,NULL,
  785.                             PGA_Top,TopLine,
  786.                         TAG_DONE);
  787.                     }
  788.                 }
  789.  
  790.                 MarkArea(BufferSearchInfo -> FoundX,LineNumber - TopLine,BufferSearchInfo -> PatternWidth);
  791.             }
  792.         }
  793.     }
  794.     else
  795.         MyEasyRequest(BufferWindow,LocaleString(MSG_GLOBAL_NOTHING_IN_THE_BUFFER_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT));
  796.  
  797.     LT_UnlockWindow(BufferWindow);
  798. }
  799.  
  800. STATIC VOID __stdargs
  801. BufferDestructor(struct MsgItem *Item)
  802. {
  803.     Signal(BufferTask,SIG_HANDSHAKE);
  804. }
  805.  
  806. STATIC BOOLEAN __regargs
  807. HandleBuffer(LONG TitleOffset)
  808. {
  809.     ULONG             LastSeconds    = 0,
  810.                  LastMicros    = 0,
  811.                  Seconds,
  812.                  Micros;
  813.     BOOLEAN             ClickAndActivate,
  814.                  UpdatePercent    = TRUE;
  815.  
  816.     ULONG             SignalSet;
  817.  
  818.     struct IntuiMessage    *Massage;
  819.     ULONG             MsgClass;
  820.     UWORD             MsgCode,MsgQualifier,LastQualifier = NULL;
  821.     WORD             MouseX,MouseY;
  822.  
  823.     UBYTE             Char,LastChar = 0;
  824.     LONG             LastWidth = 0;
  825.  
  826.     UBYTE             PercentBuffer[80];
  827.  
  828.     struct TagItem        *TagList;
  829.  
  830.     STRPTR             PercentTemplate;
  831.  
  832.     BOOLEAN             RingBack = FALSE;
  833.  
  834.     if(LocaleBase)
  835.         PercentTemplate = "%lD/%lD (%ld%%)";
  836.     else
  837.         PercentTemplate = "%ld/%ld (%ld%%)";
  838.  
  839.     do
  840.     {
  841.             /* Show where we are. */
  842.  
  843.         if(Lines && UpdatePercent)
  844.         {
  845.             LONG Width,Len;
  846.  
  847.             SetAPen(BufferScreen -> BarLayer -> rp,0);
  848.             SetBPen(BufferScreen -> BarLayer -> rp,1);
  849.             SetDrMd(BufferScreen -> BarLayer -> rp,JAM2);
  850.  
  851.             SPrintf(PercentBuffer,PercentTemplate,TopLine,Lines > NumBufferLines ? Lines - NumBufferLines : 0,(100 * (TopLine + DisplayedLines)) / Lines);
  852.  
  853.             Len = strlen(PercentBuffer);
  854.  
  855.             Move(BufferScreen -> BarLayer -> rp,TitleOffset,BufferScreen -> BarLayer -> rp -> Font -> tf_Baseline + 1);
  856.             Text(BufferScreen -> BarLayer -> rp,PercentBuffer,Len);
  857.  
  858.             Width = TextLength(BufferScreen -> BarLayer -> rp,PercentBuffer,Len);
  859.  
  860.             if(LastWidth > Width)
  861.             {
  862.                 SetAPen(BufferScreen -> BarLayer -> rp,1);
  863.  
  864.                 RectFill(BufferScreen -> BarLayer -> rp,TitleOffset + Width,1,TitleOffset + LastWidth - 1,BufferScreen -> BarLayer -> rp -> Font -> tf_YSize);
  865.             }
  866.  
  867.             LastWidth = Width;
  868.  
  869.             UpdatePercent = FALSE;
  870.         }
  871.  
  872.         SignalSet = Wait(SIG_KILL | SIG_TOFRONT | SIG_UPDATE | SIG_MOVEUP | PORTMASK(BufferWindow -> UserPort));
  873.  
  874.             /* Leave the town? */
  875.  
  876.         if(SignalSet & SIG_KILL)
  877.             BufferTerminated = RingBack = TRUE;
  878.  
  879.             /* Bring our window to the front. */
  880.  
  881.         if(SignalSet & SIG_TOFRONT)
  882.             BumpWindow(BufferWindow);
  883.  
  884.             /* We've got one more line in the
  885.              * buffer.
  886.              */
  887.  
  888.         if(SignalSet & SIG_UPDATE)
  889.         {
  890.             if(BufferLines && Lines)
  891.             {
  892.                 if(Lines - TopLine > DisplayedLines && DisplayedLines < NumBufferLines)
  893.                 {
  894.                     LONG i = TopLine + DisplayedLines;
  895.  
  896.                     do
  897.                         PrintLine(BufferLines[i++],DisplayedLines++);
  898.                     while(DisplayedLines < NumBufferLines && i < Lines);
  899.                 }
  900.             }
  901.  
  902.             SetGadgetAttrs(Scroller,BufferWindow,NULL,
  903.                 PGA_Total,    Lines,
  904.                 PGA_Visible,    DisplayedLines,
  905.             TAG_DONE);
  906.  
  907.             UpdatePercent = TRUE;
  908.  
  909.             Signal(ThisProcess,SIG_HANDSHAKE);
  910.         }
  911.  
  912.             /* The contents of the buffer have moved
  913.              * up a line.
  914.              */
  915.  
  916.         if(SignalSet & SIG_MOVEUP)
  917.         {
  918.             if(TopLine > 0)
  919.             {
  920.                 LastTopLine = --TopLine;
  921.  
  922.                 SetGadgetAttrs(Scroller,BufferWindow,NULL,
  923.                     PGA_Top,TopLine,
  924.                 TAG_DONE);
  925.             }
  926.             else
  927.             {
  928.                 LONG i;
  929.  
  930.                 MarkArea(-1,-1,-1);
  931.  
  932.                 for(i = 0 ; i < NumBufferLines - 1 ; i++)
  933.                     BufferLineWidths[i] = BufferLineWidths[i + 1];
  934.  
  935.                 ClipBlit(BPort,0,BufferLineOffsets[1],BPort,0,0,BufferColumnOffsets[NumBufferColumns],BufferLineOffsets[NumBufferLines - 1],MINTERM_COPY);
  936.  
  937.                 PrintLine(BufferLines[NumBufferLines - 1],NumBufferLines - 1);
  938.             }
  939.  
  940.             UpdatePercent = TRUE;
  941.  
  942.             Signal(ThisProcess,SIG_HANDSHAKE);
  943.         }
  944.  
  945.             /* Process the incoming window
  946.              * input.
  947.              */
  948.  
  949.         while(Massage = (struct IntuiMessage *)GetMsg(BufferWindow -> UserPort))
  950.         {
  951.             MsgClass    = Massage -> Class;
  952.             MsgCode        = Massage -> Code;
  953.             MsgQualifier    = Massage -> Qualifier;
  954.             MouseX        = Massage -> MouseX;
  955.             MouseY        = Massage -> MouseY;
  956.             TagList        = (struct TagItem *)Massage -> IAddress;
  957.             Seconds        = Massage -> Seconds;
  958.             Micros        = Massage -> Micros;
  959.  
  960.             ClickAndActivate = FALSE;
  961.  
  962.             if(Seconds == LastSeconds && Micros == LastMicros)
  963.             {
  964.                 if(Massage -> Class == IDCMP_ACTIVEWINDOW || Massage -> Class == IDCMP_MOUSEBUTTONS)
  965.                     ClickAndActivate = TRUE;
  966.             }
  967.  
  968.             LastSeconds    = Seconds;
  969.             LastMicros    = Micros;
  970.  
  971.                 /* This hack is necessary to obtain the
  972.                  * character codes generated for the cursor
  973.                  * keys. A control or alternate qualifier
  974.                  * would spoil the result (i.e. we would
  975.                  * not get a valid key code).
  976.                  */
  977.  
  978.             Massage -> Qualifier = NULL;
  979.  
  980.             Char = KeyConvert(Massage,NULL,NULL);
  981.  
  982.                 /* Just in case anybody needs it... */
  983.  
  984.             Massage -> Qualifier = MsgQualifier;
  985.  
  986.             ReplyMsg((struct Message *)Massage);
  987.  
  988.             if(MsgClass == IDCMP_ACTIVEWINDOW)
  989.                 UpdatePercent = TRUE;
  990.  
  991.             if(MsgClass == IDCMP_IDCMPUPDATE)
  992.             {
  993.                 switch(GetTagData(GA_ID,0,TagList))
  994.                 {
  995.                     case GAD_UP:
  996.  
  997.                         if(TopLine > 0)
  998.                         {
  999.                             TopLine--;
  1000.  
  1001.                             MarkArea(-1,-1,-1);
  1002.  
  1003.                             SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1004.                                 PGA_Top,TopLine,
  1005.                             TAG_DONE);
  1006.  
  1007.                             DisplayedLines = RedrawScreen(TopLine);
  1008.  
  1009.                             UpdatePercent = TRUE;
  1010.                         }
  1011.  
  1012.                         break;
  1013.  
  1014.                     case GAD_DOWN:
  1015.  
  1016.                         if(TopLine + NumBufferLines < Lines)
  1017.                         {
  1018.                             TopLine++;
  1019.  
  1020.                             MarkArea(-1,-1,-1);
  1021.  
  1022.                             SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1023.                                 PGA_Top,TopLine,
  1024.                             TAG_DONE);
  1025.  
  1026.                             DisplayedLines = RedrawScreen(TopLine);
  1027.  
  1028.                             UpdatePercent = TRUE;
  1029.                         }
  1030.  
  1031.                         break;
  1032.                 }
  1033.             }
  1034.  
  1035.             if(MsgClass == IDCMP_MOUSEMOVE || MsgClass == IDCMP_GADGETDOWN || MsgClass == IDCMP_GADGETUP)
  1036.             {
  1037.                 LONG Position;
  1038.  
  1039.                 GetAttr(PGA_Top,Scroller,(ULONG *)&Position);
  1040.  
  1041.                 if(Position != TopLine)
  1042.                 {
  1043.                     MarkArea(-1,-1,-1);
  1044.  
  1045.                     DisplayedLines = RedrawScreen(TopLine = Position);
  1046.  
  1047.                     UpdatePercent = TRUE;
  1048.                 }
  1049.             }
  1050.  
  1051.             if(MsgClass == IDCMP_RAWKEY)
  1052.             {
  1053.                 if(MsgCode == HELP_CODE)
  1054.                     GuideDisplay(CONTEXT_TEXTBUFFER);
  1055.  
  1056.                 if(LastChar)
  1057.                 {
  1058.                     if((MsgCode & IECODE_UP_PREFIX) || !(LastQualifier & IEQUALIFIER_REPEAT))
  1059.                     {
  1060.                         SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1061.                             PGA_Top,TopLine,
  1062.                         TAG_DONE);
  1063.  
  1064.                         UpdatePercent = TRUE;
  1065.                     }
  1066.                 }
  1067.  
  1068.                 if(LastChar = Char)
  1069.                 {
  1070.                         /* Use the numeric keypad keys to
  1071.                          * move through the buffer.
  1072.                          */
  1073.  
  1074.                     if(MsgQualifier & IEQUALIFIER_NUMERICPAD)
  1075.                     {
  1076.                             /* Remove the numpad qualifier. */
  1077.  
  1078.                         MsgQualifier &= ~IEQUALIFIER_NUMERICPAD;
  1079.  
  1080.                         switch(Char - '0')
  1081.                         {
  1082.                                 /* Jump to bottom. */
  1083.  
  1084.                             case 1: Char = CDN;
  1085.                                 MsgQualifier |= IEQUALIFIER_CONTROL;
  1086.                                 break;
  1087.  
  1088.                                 /* Jump to top. */
  1089.  
  1090.                             case 7: Char = CUP;
  1091.                                 MsgQualifier |= IEQUALIFIER_CONTROL;
  1092.                                 break;
  1093.  
  1094.                                 /* Move one page down. */
  1095.  
  1096.                             case 3: Char = CDN;
  1097.                                 MsgQualifier |= IEQUALIFIER_LSHIFT;
  1098.                                 break;
  1099.  
  1100.                                 /* Move one page up. */
  1101.  
  1102.                             case 9: Char = CUP;
  1103.                                 MsgQualifier |= IEQUALIFIER_LSHIFT;
  1104.                                 break;
  1105.  
  1106.                                 /* Move one line down. */
  1107.  
  1108.                             case 2: Char = CDN;
  1109.                                 break;
  1110.  
  1111.                                 /* Move one line up. */
  1112.  
  1113.                             case 8: Char = CUP;
  1114.                                 break;
  1115.                         }
  1116.                     }
  1117.  
  1118.                         /* Check cursor keys. */
  1119.  
  1120.                     switch(Char)
  1121.                     {
  1122.                             /* Scroll the buffer up. */
  1123.  
  1124.                         case CUP:
  1125.  
  1126.                             if(MsgQualifier & (IEQUALIFIER_CONTROL | IEQUALIFIER_LALT | IEQUALIFIER_RALT))
  1127.                             {
  1128.                                 MarkArea(-1,-1,-1);
  1129.  
  1130.                                 if(TopLine)
  1131.                                 {
  1132.                                     DisplayedLines = RedrawScreen(TopLine = 0);
  1133.  
  1134.                                     LastChar = 0;
  1135.  
  1136.                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1137.                                         PGA_Top,TopLine,
  1138.                                     TAG_DONE);
  1139.  
  1140.                                     UpdatePercent = TRUE;
  1141.                                 }
  1142.  
  1143.                                 break;
  1144.                             }
  1145.  
  1146.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  1147.                             {
  1148.                                 LONG NewCurrentLine;
  1149.  
  1150.                                 if((NewCurrentLine = TopLine - NumBufferLines) < 0)
  1151.                                     NewCurrentLine = 0;
  1152.  
  1153.                                 MarkArea(-1,-1,-1);
  1154.  
  1155.                                 if(NewCurrentLine != TopLine)
  1156.                                 {
  1157.                                     DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
  1158.  
  1159.                                     LastChar = 0;
  1160.  
  1161.                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1162.                                         PGA_Top,TopLine,
  1163.                                     TAG_DONE);
  1164.  
  1165.                                     UpdatePercent = TRUE;
  1166.                                 }
  1167.  
  1168.                                 break;
  1169.                             }
  1170.  
  1171.                             if(TopLine)
  1172.                             {
  1173.                                 MarkArea(-1,-1,-1);
  1174.  
  1175.                                 DisplayedLines = RedrawScreen(--TopLine);
  1176.  
  1177.                                 UpdatePercent = TRUE;
  1178.                             }
  1179.  
  1180.                             break;
  1181.  
  1182.                             /* Scroll the buffer down. */
  1183.  
  1184.                         case CDN:
  1185.  
  1186.                             if(MsgQualifier & (IEQUALIFIER_CONTROL | IEQUALIFIER_LALT | IEQUALIFIER_RALT))
  1187.                             {
  1188.                                 LONG NewCurrentLine;
  1189.  
  1190.                                 if((NewCurrentLine = Lines - NumBufferLines) < 0)
  1191.                                     NewCurrentLine = 0;
  1192.  
  1193.                                 MarkArea(-1,-1,-1);
  1194.  
  1195.                                 if(TopLine != NewCurrentLine)
  1196.                                 {
  1197.                                     DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
  1198.  
  1199.                                     LastChar = 0;
  1200.  
  1201.                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1202.                                         PGA_Top,TopLine,
  1203.                                     TAG_DONE);
  1204.  
  1205.                                     UpdatePercent = TRUE;
  1206.                                 }
  1207.  
  1208.                                 break;
  1209.                             }
  1210.  
  1211.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  1212.                             {
  1213.                                 LONG NewCurrentLine;
  1214.  
  1215.                                 if((NewCurrentLine = TopLine + (2 * NumBufferLines)) > Lines)
  1216.                                     NewCurrentLine = Lines;
  1217.  
  1218.                                 if((NewCurrentLine = NewCurrentLine - NumBufferLines) < 0)
  1219.                                     NewCurrentLine = 0;
  1220.  
  1221.                                 MarkArea(-1,-1,-1);
  1222.  
  1223.                                 if(NewCurrentLine != TopLine)
  1224.                                 {
  1225.                                     DisplayedLines = RedrawScreen(TopLine = NewCurrentLine);
  1226.  
  1227.                                     LastChar = 0;
  1228.  
  1229.                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1230.                                         PGA_Top,TopLine,
  1231.                                     TAG_DONE);
  1232.  
  1233.                                     UpdatePercent = TRUE;
  1234.                                 }
  1235.  
  1236.                                 break;
  1237.                             }
  1238.  
  1239.                             if(TopLine + NumBufferLines < Lines)
  1240.                             {
  1241.                                 MarkArea(-1,-1,-1);
  1242.  
  1243.                                 DisplayedLines = RedrawScreen(++TopLine);
  1244.  
  1245.                                 UpdatePercent = TRUE;
  1246.                             }
  1247.  
  1248.                             break;
  1249.                     }
  1250.  
  1251.                     LastQualifier = MsgQualifier;
  1252.                 }
  1253.                 else
  1254.                     LastQualifier = NULL;
  1255.  
  1256.                 continue;
  1257.             }
  1258.  
  1259.                 /* User hit a mouse button. */
  1260.  
  1261.             if(MsgClass == IDCMP_MOUSEBUTTONS && (!ClickAndActivate || MsgCode != SELECTDOWN) && !(MsgCode & IECODE_UP_PREFIX))
  1262.             {
  1263.                 MarkArea(-1,-1,-1);
  1264.  
  1265.                     /* Reasonable dimensions? */
  1266.  
  1267.                 if(MouseY / LocalTextFontHeight < DisplayedLines && MouseX / LocalTextFontWidth < NumBufferColumns)
  1268.                 {
  1269.                     ObtainSemaphore(BufferSemaphore);
  1270.  
  1271.                     BufferClip();
  1272.  
  1273.                     UpdatePercent = TRUE;
  1274.  
  1275.                     LastTopLine = TopLine;
  1276.  
  1277.                     ReleaseSemaphore(BufferSemaphore);
  1278.  
  1279.                     if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  1280.                     {
  1281.                         struct DataMsg Msg;
  1282.  
  1283.                         InitMsgItem(&Msg,BufferDestructor);
  1284.  
  1285.                         Msg . Type = DATAMSGTYPE_WRITECLIP;
  1286.                         Msg . Size = Config -> ClipConfig -> ClipboardUnit;
  1287.  
  1288.                         Forbid();
  1289.  
  1290.                         ClrSignal(SIG_HANDSHAKE);
  1291.  
  1292.                         PutMsgItem(SpecialQueue,(struct MsgItem *)&Msg);
  1293.  
  1294.                         Wait(SIG_HANDSHAKE);
  1295.  
  1296.                         Permit();
  1297.                     }
  1298.  
  1299.                     break;
  1300.                 }
  1301.             }
  1302.  
  1303.             if(MsgClass == IDCMP_MENUPICK)
  1304.             {
  1305.                 struct MenuItem *MenuItem;
  1306.  
  1307.                 while(MsgCode != MENUNULL)
  1308.                 {
  1309.                     MenuItem = ItemAddress(BufferMenuStrip,MsgCode);
  1310.  
  1311.                     switch((ULONG)GTMENUITEM_USERDATA(MenuItem))
  1312.                     {
  1313.                         case MEN_SEARCH:
  1314.  
  1315.                             StartBufferSearch(TRUE);
  1316.  
  1317.                             UpdatePercent = TRUE;
  1318.  
  1319.                             break;
  1320.  
  1321.                         case MEN_REPEAT:
  1322.  
  1323.                             StartBufferSearch(FALSE);
  1324.  
  1325.                             UpdatePercent = TRUE;
  1326.  
  1327.                             break;
  1328.  
  1329.                         case MEN_GOTO:
  1330.  
  1331.                             if(Window)
  1332.                                 BumpWindow(Window);
  1333.  
  1334.                             break;
  1335.  
  1336.                         case MEN_QUITBUF:
  1337.  
  1338.                             BufferTerminated = TRUE;
  1339.                             break;
  1340.  
  1341.                         case MEN_CLEARBUF_CONTENTS:
  1342.  
  1343.                             if(Lines)
  1344.                             {
  1345.                                 UpdatePercent = TRUE;
  1346.  
  1347.                                 LT_LockWindow(BufferWindow);
  1348.  
  1349.                                 if(MsgQualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  1350.                                 {
  1351.                                     FreeBuffer();
  1352.  
  1353.                                     LT_UnlockWindow(BufferWindow);
  1354.  
  1355.                                     FlushMsg(BufferWindow);
  1356.  
  1357.                                     DisplayedLines = RedrawScreen(TopLine = 0);
  1358.  
  1359.                                     SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1360.                                         PGA_Top,    TopLine,
  1361.                                         PGA_Total,    Lines,
  1362.                                         PGA_Visible,    NumBufferLines,
  1363.                                     TAG_DONE);
  1364.  
  1365.                                     continue;
  1366.                                 }
  1367.                                 else
  1368.                                 {
  1369.                                     if(MyEasyRequest(BufferWindow,LocaleString(MSG_TERMBUFFER_BUFFER_STILL_HOLDS_LINES_TXT),LocaleString(MSG_GLOBAL_YES_NO_TXT),Lines))
  1370.                                     {
  1371.                                         FreeBuffer();
  1372.  
  1373.                                         LT_UnlockWindow(BufferWindow);
  1374.  
  1375.                                         FlushMsg(BufferWindow);
  1376.  
  1377.                                         DisplayedLines = RedrawScreen(TopLine = 0);
  1378.  
  1379.                                         SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1380.                                             PGA_Top,    TopLine,
  1381.                                             PGA_Total,    Lines,
  1382.                                             PGA_Visible,    NumBufferLines,
  1383.                                         TAG_DONE);
  1384.  
  1385.                                         continue;
  1386.                                     }
  1387.                                 }
  1388.  
  1389.                                 LT_UnlockWindow(BufferWindow);
  1390.  
  1391.                                 FlushMsg(BufferWindow);
  1392.                             }
  1393.  
  1394.                             break;
  1395.                     }
  1396.  
  1397.                     MsgCode = MenuItem -> NextSelect;
  1398.                 }
  1399.             }
  1400.  
  1401.         }
  1402.     }
  1403.     while(!BufferTerminated);
  1404.  
  1405.     return(RingBack);
  1406. }
  1407.  
  1408.     /* BufferServer():
  1409.      *
  1410.      *    Asynchronous task to display the data stored in the
  1411.      *    scrollback display buffer.
  1412.      */
  1413.  
  1414. STATIC VOID __saveds
  1415. BufferServer(VOID)
  1416. {
  1417.     BOOLEAN             Defaults;
  1418.  
  1419.     struct ColorSpec     ColorSpec[3];
  1420.  
  1421.     LONG             Width,Height;
  1422.     ULONG             DisplayMode;
  1423.  
  1424.     struct Rectangle     DisplayClip;
  1425.     struct DimensionInfo     DimensionInfo;
  1426.  
  1427.     struct TextFont        *LocalFont;
  1428.  
  1429.     struct Task        *Father;
  1430.     BOOLEAN             RingBack = TRUE;
  1431.  
  1432.     Father = (struct Task *)SysBase -> ThisTask -> tc_UserData;
  1433.  
  1434.         /* Clone the global font data. */
  1435.  
  1436.     LocalTextFontWidth    = TextFontWidth;
  1437.     LocalTextFontHeight    = TextFontHeight;
  1438.     LocalTextFontBase    = TextFontBase;
  1439.  
  1440.     memcpy(&LocalTextFont,&TextAttr,sizeof(struct TTextAttr));
  1441.  
  1442.     LocalTextFont . tta_Name = LocalTextFontName;
  1443.  
  1444.     strcpy(LocalTextFontName,TextAttr . tta_Name);
  1445.  
  1446.     memcpy(&LocalUserFont,&UserFont,sizeof(struct TTextAttr));
  1447.  
  1448.     LocalUserFont . tta_Name = LocalUserFontName;
  1449.  
  1450.     strcpy(LocalUserFontName,UserFont . tta_Name);
  1451.  
  1452.         /* Reset top line index. */
  1453.  
  1454.     LastTopLine = -1;
  1455.  
  1456.         /* Up and running... */
  1457.  
  1458.     BufferTerminated = FALSE;
  1459.  
  1460.     Forbid();
  1461.  
  1462.     if(Window && DrawInfo)
  1463.     {
  1464.         UWORD Colour;
  1465.  
  1466.             /* Set up the startup colours for our buffer screen. */
  1467.  
  1468.         ColorSpec[0] . ColorIndex = 0;
  1469.         Colour = GetRGB4(Window -> WScreen -> ViewPort . ColorMap,DrawInfo -> dri_Pens[BACKGROUNDPEN]);
  1470.  
  1471.         ColorSpec[0] . Red        = (Colour >> 8) & 0xF;
  1472.         ColorSpec[0] . Green        = (Colour >> 4) & 0xF;
  1473.         ColorSpec[0] . Blue        = (Colour     ) & 0xF;
  1474.  
  1475.         ColorSpec[1] . ColorIndex = 1;
  1476.         Colour = GetRGB4(Window -> WScreen -> ViewPort . ColorMap,DrawInfo -> dri_Pens[TEXTPEN]);
  1477.  
  1478.         ColorSpec[1] . Red        = (Colour >> 8) & 0xF;
  1479.         ColorSpec[1] . Green        = (Colour >> 4) & 0xF;
  1480.         ColorSpec[1] . Blue        = (Colour     ) & 0xF;
  1481.  
  1482.         ColorSpec[2] . ColorIndex = -1;
  1483.  
  1484.         Defaults = FALSE;
  1485.     }
  1486.     else
  1487.         Defaults = TRUE;
  1488.  
  1489.     Permit();
  1490.  
  1491.         /* We'll use a fixed screen width, only the
  1492.          * height is adapted from the main screen.
  1493.          */
  1494.  
  1495.     DisplayMode = Config -> CaptureConfig -> BufferScreenMode;
  1496.  
  1497.     if(ModeNotAvailable(DisplayMode))
  1498.         DisplayMode = Config -> ScreenConfig -> DisplayMode;
  1499.  
  1500.     if(ModeNotAvailable(DisplayMode))
  1501.     {
  1502.         struct Screen *PubScreen = LockPubScreen(NULL);
  1503.  
  1504.         if(PubScreen)
  1505.         {
  1506.             DisplayMode = GetVPModeID(&PubScreen -> ViewPort);
  1507.  
  1508.             UnlockPubScreen(NULL,PubScreen);
  1509.         }
  1510.         else
  1511.             DisplayMode = DEFAULT_MONITOR_ID | HIRES_KEY;
  1512.     }
  1513.  
  1514.         /* Set up the actual width of the screen we want. */
  1515.  
  1516.     Width = Config -> CaptureConfig -> BufferWidth * LocalTextFontWidth + ARROW_WIDTH + 1;
  1517.  
  1518.         /* Get the mode dimension info. */
  1519.  
  1520.     if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,DisplayMode))
  1521.     {
  1522.             /* Determine maximum text overscan width. */
  1523.  
  1524.         LONG TextWidth = DimensionInfo . TxtOScan . MaxX - DimensionInfo . TxtOScan . MinX + 1;
  1525.  
  1526.             /* Too small? */
  1527.  
  1528.         if(Width < DimensionInfo . MinRasterWidth)
  1529.             Width = DimensionInfo . MinRasterWidth;
  1530.  
  1531.             /* Far too large? */
  1532.  
  1533.         if(Width > DimensionInfo . MaxRasterWidth)
  1534.             Width = DimensionInfo . MaxRasterWidth;
  1535.  
  1536.             /* A bit too large? */
  1537.  
  1538.         if(Width > TextWidth)
  1539.             Width = TextWidth;
  1540.  
  1541.         if(LocalFont = OpenFont(&LocalTextFont))
  1542.         {
  1543.                 /* Inquire the text overscan dimensions. */
  1544.  
  1545.             if(QueryOverscan(DisplayMode,&DisplayClip,OSCAN_TEXT))
  1546.             {
  1547.                     /* Centre the buffer screen. */
  1548.  
  1549.                 if(DisplayClip . MaxX - DisplayClip . MinX + 1 > Width)
  1550.                 {
  1551.                     LONG Differ = (DisplayClip . MaxX - DisplayClip . MinX + 1 - Width) / 2;
  1552.  
  1553.                     switch(Config -> CaptureConfig -> BufferScreenPosition)
  1554.                     {
  1555.                         case SCREEN_LEFT:
  1556.  
  1557.                             DisplayClip . MaxX = DisplayClip . MinX + Width;
  1558.                             break;
  1559.  
  1560.                         case SCREEN_RIGHT:
  1561.  
  1562.                             DisplayClip . MinX = DisplayClip . MaxX - Width;
  1563.                             break;
  1564.  
  1565.                         case SCREEN_CENTRE:
  1566.  
  1567.                             DisplayClip . MinX += Differ;
  1568.                             DisplayClip . MaxX -= Differ;
  1569.  
  1570.                             break;
  1571.                     }
  1572.                 }
  1573.  
  1574.                     /* Open a single bitplane clone of the main screen. */
  1575.  
  1576.                 if(BufferScreen = (struct Screen *)OpenScreenTags(NULL,
  1577.                     SA_Title,    LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT),
  1578.                     SA_Depth,    1,
  1579.                     SA_DClip,    &DisplayClip,
  1580.                     SA_DisplayID,    DisplayMode,
  1581.                     SA_Font,    &LocalUserFont,
  1582.                     SA_Behind,    TRUE,
  1583.                     SA_AutoScroll,    TRUE,
  1584.  
  1585.                     Defaults ? TAG_IGNORE : SA_Colors,ColorSpec,
  1586.                 TAG_END))
  1587.                 {
  1588.                     if(BufferVisualInfo = GetVisualInfo(BufferScreen,TAG_DONE))
  1589.                     {
  1590.                         LocalizeMenu(BufferMenu,MSG_TERMBUFFER_PROJECT_MEN);
  1591.  
  1592.                         if(BufferMenuStrip = CreateMenus(BufferMenu,TAG_DONE))
  1593.                         {
  1594.                             if(BufferDrawInfo = GetScreenDrawInfo(BufferScreen))
  1595.                             {
  1596.                                 if(!CreateMenuGlyphs(BufferScreen,BufferDrawInfo,&BufferAmigaGlyph,&BufferCheckGlyph))
  1597.                                 {
  1598.                                     FreeScreenDrawInfo(BufferScreen,BufferDrawInfo);
  1599.  
  1600.                                     BufferDrawInfo = NULL;
  1601.                                 }
  1602.                             }
  1603.  
  1604.                             if(LayoutMenus(BufferMenuStrip,BufferVisualInfo,
  1605.                                 BufferAmigaGlyph ? GTMN_AmigaKey :  TAG_IGNORE, BufferAmigaGlyph,
  1606.                                 BufferCheckGlyph ? GTMN_Checkmark : TAG_IGNORE, BufferCheckGlyph,
  1607.  
  1608.                                 GTMN_TextAttr,        &LocalUserFont,
  1609.                                 GTMN_NewLookMenus,    TRUE,
  1610.                             TAG_DONE))
  1611.                             {
  1612.                                 Height = (BufferScreen -> Height - (BufferScreen -> BarHeight + 2)) / LocalTextFontHeight;
  1613.  
  1614.                                     /* Open a cute window on our buffer screen. */
  1615.  
  1616.                                 if(BufferWindow = OpenWindowTags(NULL,
  1617.                                     WA_Top,        BufferScreen -> BarHeight + 2,
  1618.                                     WA_Left,    0,
  1619.                                     WA_Width,    BufferScreen -> Width,
  1620.                                     WA_Height,    Height * LocalTextFontHeight,
  1621.                                     WA_Backdrop,    TRUE,
  1622.                                     WA_Borderless,    TRUE,
  1623.                                     WA_SmartRefresh,FALSE,
  1624.                                     WA_CustomScreen,BufferScreen,
  1625.                                     WA_RMBTrap,    TRUE,
  1626.                                     WA_NewLookMenus,TRUE,
  1627.                                     WA_RptQueue,    1,
  1628.                                     WA_IDCMP,    IDCMP_IDCMPUPDATE | IDCMP_RAWKEY | IDCMP_INACTIVEWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_MOUSEBUTTONS | IDCMP_MENUPICK | IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_MOUSEMOVE,
  1629.  
  1630.                                     BufferAmigaGlyph ? WA_AmigaKey  : TAG_IGNORE, BufferAmigaGlyph,
  1631.                                     BufferCheckGlyph ? WA_Checkmark : TAG_IGNORE, BufferCheckGlyph,
  1632.                                 TAG_DONE))
  1633.                                 {
  1634.                                     if(BufferLineWidths = (UWORD *)AllocVecPooled(2 * sizeof(UWORD) * (BufferWindow -> Height / LocalTextFontHeight + 1) + sizeof(UWORD) * (BufferWindow -> Width / LocalTextFontWidth + 1),MEMF_ANY | MEMF_CLEAR))
  1635.                                     {
  1636.                                         UWORD    Index;
  1637.                                         WORD    i;
  1638.  
  1639.                                         BufferLineOffsets    = &BufferLineWidths[BufferWindow -> Height / LocalTextFontHeight + 1];
  1640.                                         BufferColumnOffsets    = &BufferLineOffsets[BufferWindow -> Height / LocalTextFontHeight + 1];
  1641.  
  1642.                                         for(i = Index = 0 ; i < BufferWindow -> Height / LocalTextFontHeight + 1 ; i++)
  1643.                                         {
  1644.                                             BufferLineOffsets[i] = Index;
  1645.  
  1646.                                             Index += LocalTextFontHeight;
  1647.                                         }
  1648.  
  1649.                                         for(i = Index = 0 ; i < BufferWindow -> Width / LocalTextFontWidth + 1 ; i++)
  1650.                                         {
  1651.                                             BufferColumnOffsets[i] = Index;
  1652.  
  1653.                                             Index += LocalTextFontWidth;
  1654.                                         }
  1655.  
  1656.                                         if(CreateScroller(BufferWindow -> Height))
  1657.                                         {
  1658.                                                 /* Signal our father process that
  1659.                                                  * we're running.
  1660.                                                  */
  1661.  
  1662.                                             Signal(Father,SIG_HANDSHAKE);
  1663.  
  1664.                                             Father = NULL;
  1665.  
  1666.                                             ObtainSemaphore(&BufferTaskSemaphore);
  1667.  
  1668.                                             BufferTask = SysBase -> ThisTask;
  1669.  
  1670.                                             ReleaseSemaphore(&BufferTaskSemaphore);
  1671.  
  1672.                                             SetMenuStrip(BufferWindow,BufferMenuStrip);
  1673.  
  1674.                                             AddGList(BufferWindow,Scroller,(UWORD)-1,(UWORD)-1,NULL);
  1675.                                             RefreshGList(Scroller,BufferWindow,NULL,(UWORD)-1);
  1676.  
  1677.                                                 /* Determine maximum dimensions of
  1678.                                                  * the buffer screen (in rows and
  1679.                                                  * columns).
  1680.                                                  */
  1681.  
  1682.                                             NumBufferColumns    = (BufferWindow -> Width - (ARROW_WIDTH + 1)) / LocalTextFontWidth;
  1683.                                             NumBufferLines        = BufferWindow -> Height / LocalTextFontHeight;
  1684.  
  1685.                                             if(TopLine == -1 || !Config -> CaptureConfig -> RememberBufferScreen)
  1686.                                             {
  1687.                                                 switch(Config -> CaptureConfig -> OpenBufferScreen)
  1688.                                                 {
  1689.                                                     case BUFFER_TOP:
  1690.  
  1691.                                                         TopLine = 0;
  1692.                                                         break;
  1693.  
  1694.                                                     case BUFFER_END:
  1695.  
  1696.                                                         if((TopLine = Lines - NumBufferLines) < 0)
  1697.                                                             TopLine = 0;
  1698.  
  1699.                                                         break;
  1700.  
  1701.                                                     default:
  1702.  
  1703.                                                         TopLine = 0;
  1704.                                                         break;
  1705.                                                 }
  1706.                                             }
  1707.  
  1708.                                             if(TopLine > Lines - NumBufferLines)
  1709.                                                 TopLine = 0;
  1710.  
  1711.                                             BPort = BufferWindow -> RPort;
  1712.  
  1713.                                             SetFont(BPort,LocalFont);
  1714.  
  1715.                                                 /* Bring the screen to the front. */
  1716.  
  1717.                                             BumpWindow(BufferWindow);
  1718.  
  1719.                                                 /* Set the drawing pens for the window. */
  1720.  
  1721.                                             SetAPen(BPort,1);
  1722.                                             SetBPen(BPort,0);
  1723.                                             SetDrMd(BPort,JAM2);
  1724.  
  1725.                                                 /* Initial creation of the buffer display. */
  1726.  
  1727.                                             DisplayedLines = RedrawScreen(TopLine);
  1728.  
  1729.                                             SetGadgetAttrs(Scroller,BufferWindow,NULL,
  1730.                                                 PGA_Top,    TopLine,
  1731.                                                 PGA_Total,    Lines,
  1732.                                                 PGA_Visible,    NumBufferLines,
  1733.                                             TAG_DONE);
  1734.  
  1735.                                             BufferWindow -> Flags &= ~WFLG_RMBTRAP;
  1736.  
  1737.                                             RingBack = HandleBuffer(TextLength(BufferScreen -> BarLayer -> rp,LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT),strlen(LocaleString(MSG_TERMBUFFER_TERM_BUFFER_TXT))) + TextLength(BufferScreen -> BarLayer -> rp," ",1) + 4);
  1738.  
  1739.                                             RemoveGList(BufferWindow,Scroller,(UWORD)-1);
  1740.  
  1741.                                             DeleteScroller();
  1742.                                         }
  1743.  
  1744.                                         FreeVecPooled(BufferLineWidths);
  1745.                                     }
  1746.  
  1747.                                     if(Window)
  1748.                                         BumpWindow(Window);
  1749.  
  1750.                                     MarkArea(-1,-1,-1);
  1751.  
  1752.                                     ScreenToBack(BufferScreen);
  1753.  
  1754.                                     BufferWindow -> Flags |= WFLG_RMBTRAP;
  1755.  
  1756.                                     ClearMenuStrip(BufferWindow);
  1757.  
  1758.                                     LT_DeleteWindowLock(BufferWindow);
  1759.  
  1760.                                     CloseWindow(BufferWindow);
  1761.                                 }
  1762.                             }
  1763.  
  1764.                             DisposeObject(BufferAmigaGlyph);
  1765.                             DisposeObject(BufferCheckGlyph);
  1766.  
  1767.                             FreeScreenDrawInfo(BufferScreen,BufferDrawInfo);
  1768.  
  1769.                             FreeMenus(BufferMenuStrip);
  1770.                         }
  1771.  
  1772.                         FreeVisualInfo(BufferVisualInfo);
  1773.                     }
  1774.  
  1775.                     CloseScreen(BufferScreen);
  1776.                 }
  1777.             }
  1778.  
  1779.             CloseFont(LocalFont);
  1780.         }
  1781.     }
  1782.  
  1783.         /* Release the search buffer data. */
  1784.  
  1785.     if(BufferSearchInfo)
  1786.     {
  1787.         DeleteSearchInfo(BufferSearchInfo);
  1788.  
  1789.         BufferSearchInfo = NULL;
  1790.     }
  1791.  
  1792.     ObtainSemaphore(&BufferTaskSemaphore);
  1793.  
  1794.     Forbid();
  1795.  
  1796.     BufferTask = NULL;
  1797.  
  1798.     ReleaseSemaphore(&BufferTaskSemaphore);
  1799.  
  1800.     if(RingBack)
  1801.     {
  1802.         if(Father)
  1803.             Signal(Father,SIG_HANDSHAKE);
  1804.         else
  1805.             Signal(ThisProcess,SIG_HANDSHAKE);
  1806.     }
  1807. }
  1808.  
  1809.     /* LaunchBuffer():
  1810.      *
  1811.      *    Launch the buffer process.
  1812.      */
  1813.  
  1814. BYTE
  1815. LaunchBuffer()
  1816. {
  1817.     ObtainSemaphore(&BufferTaskSemaphore);
  1818.  
  1819.         /* Is the buffer process already running? */
  1820.  
  1821.     if(BufferTask)
  1822.     {
  1823.             /* Tell it to bring its screen to the front. */
  1824.  
  1825.         Signal(BufferTask,SIG_TOFRONT);
  1826.  
  1827.         ReleaseSemaphore(&BufferTaskSemaphore);
  1828.  
  1829.             /* Return success. */
  1830.  
  1831.         return(TRUE);
  1832.     }
  1833.     else
  1834.     {
  1835.         struct Task    *Child;
  1836.         BYTE         Result = FALSE;
  1837.  
  1838.         ReleaseSemaphore(&BufferTaskSemaphore);
  1839.  
  1840.         Forbid();
  1841.  
  1842.             /* Launch the buffer process. */
  1843.  
  1844.         if(Child = (struct Task *)CreateNewProcTags(
  1845.             NP_Entry,    BufferServer,
  1846.             NP_Name,    "term Buffer Process",
  1847.             NP_Priority,    SysBase -> ThisTask -> tc_Node . ln_Pri,
  1848.             NP_StackSize,    4000,
  1849.             NP_WindowPtr,    -1,
  1850.         TAG_END))
  1851.         {
  1852.             Child -> tc_UserData = SysBase -> ThisTask;
  1853.  
  1854.             ClrSignal(SIG_HANDSHAKE);
  1855.  
  1856.             Wait(SIG_HANDSHAKE);
  1857.  
  1858.             ObtainSemaphore(&BufferTaskSemaphore);
  1859.  
  1860.             if(BufferTask)
  1861.                 Result = TRUE;
  1862.  
  1863.             ReleaseSemaphore(&BufferTaskSemaphore);
  1864.         }
  1865.  
  1866.         Permit();
  1867.  
  1868.             /* Return the result. */
  1869.  
  1870.         return(Result);
  1871.     }
  1872. }
  1873.  
  1874.     /* TerminateBuffer():
  1875.      *
  1876.      *    Terminate the buffer process.
  1877.      */
  1878.  
  1879. VOID
  1880. TerminateBuffer()
  1881. {
  1882.     ObtainSemaphore(&BufferTaskSemaphore);
  1883.  
  1884.     if(BufferTask)
  1885.     {
  1886.         Forbid();
  1887.  
  1888.         Signal(BufferTask,SIG_KILL);
  1889.  
  1890.         ReleaseSemaphore(&BufferTaskSemaphore);
  1891.  
  1892.         ClrSignal(SIG_HANDSHAKE);
  1893.  
  1894.         Wait(SIG_HANDSHAKE);
  1895.  
  1896.         Permit();
  1897.     }
  1898.     else
  1899.         ReleaseSemaphore(&BufferTaskSemaphore);
  1900.  
  1901.     LastTopLine = -1;
  1902. }
  1903.